#include "uart/uart_driver.h"
#include "uart/uart_hal.h"

#if (DEVICE_DEBUG > DEVICE_DEBUG_OFF)
static const char *TAG = "UART_DRIVER";
#endif

#define UART_DRIVER_TX_RINGBUF_SIZE (1024)
#define UART_DRIVER_RX_RINGBUF_SIZE (1024)

DEVICE_PUBLIC(static const uart_hal_driver_ops_t *) uart_hal_drv_ops = &uart_hal_driver_stm32;
DEVICE_PUBLIC(static uart_private_context_t *) uart_context_head = NULL;



DEVICE_PUBLIC(static int) uart_context_add(uart_private_context_t *context) {
    if (!context) {
        return -1;
    }
    uart_private_context_t *cur = uart_context_head;
    while (cur) {
        if (cur == context) {
            return 0;
        }
        cur = cur->next;
    }
    context->next = uart_context_head;
    uart_context_head = context;

    return 0;
}

DEVICE_PUBLIC(static int) uart_context_remove(uart_private_context_t *context) {
    if (!context || !uart_context_head) {
        return -1;
    }

    uart_private_context_t *prev = NULL;
    uart_private_context_t *cur = uart_context_head;

    while (cur) {
        if (cur == context) {
            if (prev) {
                prev->next = cur->next;
            } else {
                uart_context_head = cur->next;
            }
            return 0;
        }
        prev = cur;
        cur = cur->next;
    }

    return -2; // context not found
}


DEVICE_PUBLIC(static int) uart_driver_device_valid_checked(uart_device_t *dev) {
    if (!dev || !dev->private_data || !uart_hal_drv_ops) {
        return -1;
    }

    uart_private_context_t *private_context = dev->private_data;
    if (private_context->port <= UART_PORT_ENUM_MIN || private_context->port > UART_PORT_ENUM_MAX) {
        return -2;
    }
    return 0;
}


DEVICE_PUBLIC(static int) uart_driver_open(uart_device_t *dev, va_list args) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    
    uart_device_config_t *uart_cfg = va_arg(args, uart_device_config_t *);
    if (!uart_cfg) {
        return -2;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status) {
        return -3;
    }
    memcpy(&uart_context->uart_cfg, uart_cfg, sizeof(uart_device_config_t));

    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -4;
    }
    ring_buffer_t *rx_rb_obj = &uart_context->uart_cfg.data_cfg.rx_ringbuf;
    ring_buffer_t *tx_rb_obj = &uart_context->uart_cfg.data_cfg.tx_ringbuf;
    uint32_t tx_rb_size = DEVICE_GET_VALID_VALUE(uart_context->uart_cfg.data_cfg.tx_fifo_size, 0, UART_DRIVER_TX_RINGBUF_SIZE);
    uint32_t rx_rb_size = DEVICE_GET_VALID_VALUE(uart_context->uart_cfg.data_cfg.rx_fifo_size, 0, UART_DRIVER_RX_RINGBUF_SIZE);
    uart_context->uart_cfg.data_cfg.tx_fifo_size = tx_rb_size;
    uart_context->uart_cfg.data_cfg.rx_fifo_size = rx_rb_size;

    if (ringbuf_init(rx_rb_obj, rx_rb_size) != 0) {
        return -5;
    }
    if (ringbuf_init(tx_rb_obj, tx_rb_size) != 0) {
        ringbuf_free(rx_rb_obj);
        return -5;
    }
    uart_context->open_status = true;

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_close(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    if (uart_hal_drv_ops->hal_uart_deinit(uart_context->port) != 0) {
        return -3;
    }
    if (uart_hal_drv_ops->hal_uart_isr_disable(uart_context->port)) {
        return -4;
    }
    ringbuf_free(&uart_context->uart_cfg.data_cfg.rx_ringbuf);
    ringbuf_free(&uart_context->uart_cfg.data_cfg.tx_ringbuf);
    memset(&uart_context->uart_cfg, 0, sizeof(uart_device_config_t));
    uart_context->open_status = false;
    
    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_set_baudrate(uart_device_t *dev, uart_device_baudrate_t baudrate) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->uart_cfg.baudrate = baudrate;
    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -3;
    }

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_set_databits(uart_device_t *dev, uart_device_data_bits_t databits) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->uart_cfg.databits = databits;
    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -3;
    }

    return 0;
}


DEVICE_PUBLIC(static int) uart_driver_set_stopbits(uart_device_t *dev, uart_device_stop_bits_t stopbits) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->uart_cfg.stopbits = stopbits;
    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -3;
    }

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_set_parity(uart_device_t *dev, uart_device_parity_t parity) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->uart_cfg.parity = parity;
    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -3;
    }

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_set_flowctrl(uart_device_t *dev, uart_device_flow_control_t flowctrl) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->uart_cfg.flowctrl = flowctrl;
    if (uart_hal_drv_ops->hal_uart_init(uart_context->port, &uart_context->uart_cfg) != 0) {
        return -3;
    }

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_isr_enable(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
            return -1;
        }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->irq_enable_status = true;
    if (uart_hal_drv_ops->hal_uart_isr_enable(uart_context->port) != 0) {
        return -3;
    }
    
    return 0;
}


DEVICE_PUBLIC(static int) uart_driver_isr_disable(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
            return -1;
        }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->irq_enable_status = false;
    if (uart_hal_drv_ops->hal_uart_isr_disable(uart_context->port) != 0) {
        return -3;
    }
    return 0;
}


DEVICE_PUBLIC(static int) uart_driver_lowpower_enter(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
            return -1;
        }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    if (uart_hal_drv_ops->hal_uart_lowpower_enter(uart_context->port) != 0) {
        return -3;
    }
    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_lowpower_exit(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    if (uart_hal_drv_ops->hal_uart_lowpower_exit(uart_context->port) != 0) {
        return -3;
    }
    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_event_cb_add(uart_device_t *dev, uart_event_cb evt_cb, void *user_data) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->evt.evt_cb = evt_cb;
    uart_context->evt.user_data = user_data;

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_event_cb_remove(uart_device_t *dev) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    uart_context->evt.evt_cb = NULL;
    uart_context->evt.user_data = NULL;

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_transmit(uart_device_t *dev, const void *data, uint32_t len) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    ring_buffer_t *rb_obj = &uart_context->uart_cfg.data_cfg.tx_ringbuf;
    if (ringbuf_free_space(rb_obj) < len) {
        return -3;
    }
    uint32_t t_len = ringbuf_write(rb_obj, data, len);
    if (t_len != len) {
        return -4;
    }

    return 0;
}

DEVICE_PUBLIC(static int) uart_driver_received(uart_device_t *dev, void *data, uint32_t len) {
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -1;
    }
    uart_private_context_t *uart_context = dev->private_data;
    if (uart_context->open_status != true) {
        return -2;
    }
    ring_buffer_t *rb_obj = &uart_context->uart_cfg.data_cfg.rx_ringbuf;

    return ringbuf_read(rb_obj, data, len);
}

DEVICE_PUBLIC(static int) uart_driver_ioctl(uart_device_t *dev, va_list args) {
    if (!dev || !dev->drv || !((driver_t *)dev->drv)->private_ops) {
        return -1;
    }

    uart_driver_ops_t *uart_ops = (uart_driver_ops_t *)((driver_t *)dev->drv)->private_ops;
    uart_ctrl_cmd_t uart_ctrl_cmd = (uart_ctrl_cmd_t)va_arg(args, int);

    switch (uart_ctrl_cmd)
    {
    case UART_CTRL_CMD_NONE:
        return 0;

    case UART_CTRL_CMD_SET_BAUDRATE:
    {
        uart_device_baudrate_t baudrate = (uart_device_baudrate_t)va_arg(args, int);
        if (!uart_ops->uart_set_baudrate)
        {
            return -2;
        }
        return uart_ops->uart_set_baudrate(dev, baudrate);
    }

    case UART_CTRL_CMD_SET_DATABITS:
    {
        if (!uart_ops->uart_set_baudrate)
        {
            return -2;
        }
        uart_device_data_bits_t databits = (uart_device_data_bits_t)va_arg(args, int);
        return uart_ops->uart_set_databits(dev, databits);
    }

    case UART_CTRL_CMD_SET_PARITY:
    {
        if (!uart_ops->uart_set_parity)
        {
            return -2;
        }
        uart_device_parity_t parity = (uart_device_parity_t)va_arg(args, int);
        return uart_ops->uart_set_parity(dev, parity);
    }

    case UART_CTRL_CMD_SET_STOPBITS:
    {
        if (!uart_ops->uart_set_stopbits)
        {
            return -2;
        }
        uart_device_stop_bits_t stopbits = (uart_device_stop_bits_t)va_arg(args, int);
        return uart_ops->uart_set_stopbits(dev, stopbits);
    }

    case UART_CTRL_CMD_FLOWCTRL:
    {
        if (!uart_ops->uart_set_flowctrl)
        {
            return -2;
        }
        uart_device_flow_control_t flowctrl = (uart_device_flow_control_t)va_arg(args, int);
        return uart_ops->uart_set_flowctrl(dev, flowctrl);
    }

    case UART_CTRL_CMD_SET_ISR_ENABLE:
    {
        if (!uart_ops->uart_isr_enable)
        {
            return -2;
        }
        return uart_ops->uart_isr_enable(dev);
    }

    case UART_CTRL_CMD_SET_ISR_DISABLE:
    {
        if (!uart_ops->uart_isr_disable)
        {
            return -2;
        }
        return uart_ops->uart_isr_disable(dev);
    }

    case UART_CTRL_CMD_SET_EVENT_CB_ADD:
    {
        if (!uart_ops->uart_event_handle_add)
        {
            return -2;
        }
        uart_event_cb cb = (uart_event_cb)va_arg(args, void *);
        void *user_data = va_arg(args, void *);
        return uart_ops->uart_event_handle_add(dev, cb, user_data);
    }

    case UART_CTRL_CMD_SET_EVENT_CB_REMOVE:
    {
        if (!uart_ops->uart_event_handle_remove)
        {
            return -2;
        }
        return uart_ops->uart_event_handle_remove(dev);
    }

    case UART_CTRL_CMD_SET_LOWPOWER_ENTER:
    {
        if (!uart_ops->uart_set_lowpower_enter)
        {
            return -2;
        }
        return uart_ops->uart_set_lowpower_enter(dev);
    }
    case UART_CTRL_CMD_SET_LOWPOWER_EXIT:
    {
        if (!uart_ops->uart_set_lowpower_exit)
        {
            return -2;
        }
        return uart_ops->uart_set_lowpower_exit(dev);
    }

    default:
        return -99;
    }
}

DEVICE_PUBLIC(static int) uart_driver_read(uart_device_t *dev, void *data, uint32_t len) {
    return uart_driver_received(dev, data, len);
}

DEVICE_PUBLIC(static int) uart_driver_write(uart_device_t *dev, const void *data, uint32_t len) {
    return uart_driver_transmit(dev, data, len);
}

DEVICE_PUBLIC(static int) uart_driver_probe(void *dev, void *drv) {
    if (!dev || !drv) {
        return -1;
    }

    uart_device_t *thisdev = dev;
    driver_t *thisdrv = drv;

    uart_device_port_t uart_port = (uart_device_port_t)(uintptr_t)thisdev->user_data;
    if (uart_port <= UART_PORT_ENUM_MIN || uart_port > UART_PORT_ENUM_MAX) {
        return -2;
    }
    uart_private_context_t *private_context = (uart_private_context_t *)DEVICE_MALLOC(sizeof(uart_private_context_t));
    if (!private_context) {
        return -3;
    }

    memset(private_context, 0, sizeof(uart_private_context_t));
    private_context->dev = dev;
    private_context->port = uart_port;
    thisdev->drv = thisdrv;
    thisdev->private_data = private_context;
    thisdev->ops = thisdrv->ops;
    uart_context_add(private_context);
    DEVICE_LOG_DEBUG(TAG, "dev[%s] probe drv[%s] success", thisdev->name, thisdrv->name);

    return 0;
}


DEVICE_PUBLIC(static int) uart_driver_remove(void *dev, void *drv) {
    if (!dev || !drv) {
        return -1;
    }
    if (uart_driver_device_valid_checked(dev) != 0) {
        return -2;
    }
    uart_device_t *thisdev = dev;
    uart_private_context_t *private_context = thisdev->private_data;
    if (private_context) {
        uart_context_remove(private_context);
        DEVICE_FREE(private_context);
        private_context = NULL;
    }
    thisdev->drv = NULL;
    thisdev->ops = NULL;

    return 0;
}

DEVICE_PUBLIC(void) uart_driver_isr_received_handler(uart_device_port_t uart_port, void *data, uint32_t len) {
    if (uart_port <= UART_PORT_ENUM_MIN || uart_port > UART_PORT_ENUM_MAX) {
        return;
    }

    uart_private_context_t *cur_node = uart_context_head;
    for (; cur_node; cur_node = cur_node->next) {
        if (cur_node->open_status && cur_node->irq_enable_status && !cur_node->is_busy) {
            if (cur_node->port == uart_port) {
                cur_node->is_busy = true;
                uint32_t w_len = 0;
                w_len = ringbuf_write(&cur_node->uart_cfg.data_cfg.rx_ringbuf, data, len);
                if (w_len < len)
                {
                    if (cur_node->evt.evt_cb) {
                        cur_node->evt.evt_cb(cur_node->dev, UART_EVENT_FIFO_OVERFLOW, NULL, cur_node->evt.user_data);
                    }
                }
                else
                {
                    if (cur_node->evt.evt_cb) {
                        cur_node->evt.evt_cb(cur_node->dev, UART_EVENT_DATA, NULL, cur_node->evt.user_data);
                    }
                }
                cur_node->is_busy = false;
            }
        }
    }
}

DEVICE_PUBLIC(void) uart_driver_transmit_handler(void) {
    uart_private_context_t *cur_node = uart_context_head;
    for (; cur_node; cur_node = cur_node->next) {
        if (uart_driver_device_valid_checked(cur_node->dev) != 0) {
            continue;
        }
        if (cur_node->open_status && !cur_node->is_busy) {
            uint32_t r_len = 0;
            uint8_t s_buffer[128] = {0};
            cur_node->is_busy = true;
            r_len = ringbuf_read(&cur_node->uart_cfg.data_cfg.tx_ringbuf, s_buffer, sizeof(s_buffer));
            if (r_len) {
                if (uart_hal_drv_ops->hal_uart_transmit) {
                    uart_hal_drv_ops->hal_uart_transmit(cur_node->port, s_buffer, r_len);
                }
            }
            cur_node->is_busy = false;
        }
    }
}

DEVICE_PUBLIC(static const uart_driver_ops_t) uart_driver_ops = {
    .uart_set_baudrate = uart_driver_set_baudrate,
    .uart_set_databits = uart_driver_set_databits,
    .uart_set_flowctrl = uart_driver_set_flowctrl,
    .uart_set_parity = uart_driver_set_parity,
    .uart_set_stopbits = uart_driver_set_stopbits,
    .uart_isr_disable = uart_driver_isr_disable,
    .uart_isr_enable = uart_driver_isr_enable,
    .uart_set_lowpower_enter = uart_driver_lowpower_enter,
    .uart_set_lowpower_exit = uart_driver_lowpower_exit,
    .uart_event_handle_add = uart_driver_event_cb_add,
    .uart_event_handle_remove = uart_driver_event_cb_remove,
};

DEVICE_PUBLIC(static const device_ops_t) uart_device_ops = {
    .open = uart_driver_open,
    .close = uart_driver_close,
    .ioctl = uart_driver_ioctl,
    .read = uart_driver_read,
    .write = uart_driver_write,
};

DEVICE_PUBLIC(driver_t) uart_device_driver = {
    .name = "uart",
    .type = DEVICE_TYPE_UART,
    .compat = "generic,uart",
    .probe = uart_driver_probe,
    .remove = uart_driver_remove,
    .ops = &uart_device_ops,
    .private_ops = &uart_driver_ops,
    .bus = NULL,
};
